package sengine;

import game.Bullet;
import game.Weapon;
import java.util.ArrayList;

/**
 * Physics is phun no its not
 *
 * @author twoodf5611
 */
public class PhysicsEngine {

    private final CollisionDetector coldet = new CollisionDetector();
    private final ArrayList<Object2D> objects = new ArrayList<>();

    /**
     * Add an object to be tracked
     *
     * @param obj The object to add
     */
    public void addObject(Object2D obj) {
        coldet.addObject(obj);
        objects.add(obj);
    }

    public void removeObject(Object2D obj) {
        coldet.removeObject(obj);
        objects.remove(obj);
    }

    public void update(long millis) {
        // Collisions
        coldet.update();
        // Evaluate collisions
        for (Collision coll : coldet.getCollisions()) {
            //System.out.println(coll);
            Object2D obj1 = coll.getObj1();
            Object2D obj2 = coll.getObj2();
            switch (obj2.getPhysType()) {
                case FIXED:
                    switch (obj1.getPhysType()) {
                        case FIXED:
                            break;
                        case MOVABLE:
                            fixedMovableCollide(obj2, obj1, (byte) -coll.getXdirection(), (byte) -coll.getYdirection());
                            break;
                        case BULLET:
                            if (obj1 instanceof Sprite) {
                                ((Sprite) obj1).rmSelf();
                            }
                            break;
                    }
                    break;
                case MOVABLE:
                    switch (obj1.getPhysType()) {
                        case FIXED:
                            fixedMovableCollide(obj1, obj2, coll.getXdirection(), coll.getYdirection());
                            break;
                        case MOVABLE:
                            inertialCollide(coll);
                            break;
                        case BULLET:
                            //bulletMovableCollide(obj1, obj2);
                            break;
                    }
                    break;
                case BULLET:
                    switch (obj1.getPhysType()) {
                        case FIXED:
                            if (obj1 instanceof Sprite) {
                                Sprite spr2 = (Sprite) obj2;
                                spr2.rmSelf();
                            }
                            break;
                        case MOVABLE:
                            //bulletMovableCollide(obj2, obj1);
                            break;
                    }
                    break;
            }
            if(obj1 instanceof Weapon) {
                bulletMovableCollide(obj1, obj2);
            } else if (obj2 instanceof Weapon) {
                bulletMovableCollide(obj2, obj1);
            }
        }

        for (Object2D obj : objects) {
            obj.kinematicsUpdate(millis);
        }

        // Reset everything
        for (Object2D obj : objects) {
            obj.setAr(0);
            obj.setAx(0);
            if (obj.getPhysType() == Object2D.PhysicsType.MOVABLE) {
                obj.setAy(300);
            }
        }
    }

    private void bulletMovableCollide(Object2D bullet, Object2D movable) {
        if (movable instanceof Character && bullet instanceof Weapon) {
            ((Weapon) bullet).collideTarget((Character) movable);
        } else {
            //inertialCollide() maybe?
        }
    }

    private void fixedMovableCollide(Object2D fixed, Object2D movable, byte x, byte y) {
//        System.out.println("y=" + y + ", x=" + x + ", movable=" + movable);
        if (x == 0) {
            if (movable.getVy() < 0 && y > -1 && movable.getY() > fixed.getY()) {
//                System.out.println("a " + movable);
                movable.setVy(Math.abs(movable.getVy()) / 2);
                movable.setAy(400);
                movable.setY(fixed.getY() + fixed.getHeight() + 2);
            } else if (movable.getVy() > 0 && y < 1) {
//                System.out.println("b " + movable + " " + y);
                movable.setVy(0);
                movable.setAy(0);
                movable.setY(fixed.getY() - movable.getHeight());
                if (movable instanceof Character) {
                    ((Character) movable).onGround();
                }
            }
        }

        if (x == 1 && movable.getVx() > 0) {
            movable.setVx(0);
            movable.setAx(0);
            movable.setX(fixed.getX() - movable.getWidth() - 2);
        } else if (x == -1 && movable.getVx() < 0) {
            movable.setVx(0);
            movable.setAx(0);
            movable.setX(fixed.getX() + fixed.getWidth() + 2);
        }
    }

    private void inertialCollide(Collision coll) {
        // Conservation of momentum!!!!!
        // Not exactly accurate in all cases, but hopefully close enough
        Object2D obj1 = coll.getObj1();
        Object2D obj2 = coll.getObj2();
//        System.out.println(obj1.getX() + ", " + obj2.getX() + ", " + coll.getXdirection());
        float mx = obj1.getVx() * obj1.getMass() + obj2.getVx() * obj2.getMass();
        float my = obj1.getVy() * obj1.getMass() + obj2.getVy() * obj2.getMass();
        if ((obj2.getX() - obj1.getX()) * mx > 0) {
            float vx = mx / (obj1.getMass() + obj2.getMass());
            float vy = my / (obj1.getMass() + obj2.getMass());
            obj1.setVx(vx);
            //obj1.setVy(vy);
            obj2.setVx(vx);
            //obj2.setVy(vy);
        }
    }
}
